/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Shared Datatypes and Utilities.

Shared Datatypes and Utilities is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Shared Datatypes and Utilities is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Shared Datatypes and Utilities.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include "non0string.h"
#include "linkedlist.h"
#include "helpers.h"

char *getabspath(const char *relative, const char *base) {
	LinkedList *buildpath, *exampath;
	ListNode *walker;
	non0string *root, *part, *temppart, *ssbase, *ssrel;
	
	int append;
   
	size_t finallength;
	char *finalstr, *fbd;
		
	
	ssbase = char2non((const unsigned char*)base);
	ssrel = char2non((const unsigned char*)relative);
	buildpath = SplitString(ssbase, "\\/");
	exampath = SplitString(ssrel, "\\/");
	n0sfree(ssrel);
	n0sfree(ssbase);
	
	if (exampath->nodes == 0) {
		LLdelete(buildpath, (FREEFUNC*)n0sfree);
		LLdelete(exampath, (FREEFUNC*)n0sfree);
		finallength = strlen(base)+1;
		finalstr = (char*)malloc(sizeof(char)*finallength);
		strcpy(finalstr, base);
		return finalstr;
	}
	
	if (*base == '\\' || *base == '/') {
		/* Unix type file system */
		root = n0salloc(0);
	}
	else {
		/* Windows type file system */
		root = (non0string*)LLdelFirst(buildpath);
	}
	if (*relative == '\\' || *relative == '/') {
		/* Start building from root */
		LLdelete(buildpath, (FREEFUNC*)n0sfree);
		buildpath = LLcreate();
	}
	else {
		part = (non0string*)exampath->first->x;
		if (root->l > 0) {
			if (part->s[part->l-1] == ':') {
				/* Absolute windows path with drive letter */
				n0sfree(root);
				root = (non0string*)LLdelFirst(exampath);
				LLdelete(buildpath, (FREEFUNC*)n0sfree);
				buildpath = LLcreate();
			}
		}
	}
	LLaddFirst(buildpath, root);
	finallength=0;
	walker = buildpath->first;
	while (walker) {
		part = (non0string*)walker->x;
		finallength += part->l+1;
		walker = walker->next;
	}
	while (exampath->nodes) {
		append = 1;
		part = (non0string*)LLdelFirst(exampath);
		if (part->l == 0) {
			/* empty, disregard */
			append = 0;
		}
		else {
			if (part->l == 1) {
				if (*(part->s) == '.') {
					/* Self, disregard */
					append = 0;
				}
			}
			else if (part->l == 2) {
				if (strncmp((char *)(part->s), "..", 2) == 0) {
					/* Parent folder */
					if (buildpath->nodes == 1) {
						/* Already in root, there is no parent folder! */
						LLdelete(buildpath, (FREEFUNC*)n0sfree);
						LLdelete(exampath, (FREEFUNC*)n0sfree);
						return NULL;
					}
					temppart = (non0string*)LLdelLast(buildpath);
					finallength -= (temppart->l + 1);
					n0sfree(temppart);
					append = 0;
				}
			}
		}
		if (append) {
			LLaddLast(buildpath, part);
			finallength += part->l + 1;
		}
		else {
			n0sfree(part);
		}
	}
	finalstr = (char*)malloc(finallength);
	fbd = finalstr;
	while (buildpath->nodes) {
		part = (non0string*)LLdelFirst(buildpath);
		memcpy(fbd,part->s,part->l);
		fbd += part->l;
		*fbd = '/';
		fbd++;
		n0sfree(part);
	}
	*(--fbd) = 0;
	LLdelete(exampath, (FREEFUNC*)n0sfree);
	LLdelete(buildpath, (FREEFUNC*)n0sfree);
	return finalstr;
}
